﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;


namespace UML_editor_Class_Diagam_v1._0
{
    
    public partial class Form1 : Form
    {
        public static bool isLinkAction;//режим построения связей
        private Point p;
        private Size s;
        private string file_name;

        private int delete_type;            //тип удаленного элемента
        private class_element cancel_class; //переменная для сохранения параметров удаленного класса
        private string cancel_comment;      //переменная для сохранения параметров удаленного комментария
        private int x_cancel;               //координаты удаленного элемента
        private int y_cancel;

        //ТЕСТОВЫЕ КООРДИНАТЫ ВХОДА-ВЫХОДА СВЯЗЕЙ!!! ПОТОМ НЕОБХОДИМО БУДЕТ СДЕЛАТЬ КОНТЕЙНЕР СВЯЗЕЙ!!!
        private int x_out;
        private int y_out;
        private int x_in;
        private int y_in;

        private bool sender_choose;//если иточник связи уже известен, но true

        public Form1()
        {
            InitializeComponent();
            Button_Cancel.Click += cancel_Last_Delete;
            отменитьToolStripMenuItem.Click += cancel_Last_Delete;
            сохранитьКакToolStripMenuItem.Click += сохранитьКакToolStripMenuItem_Click;
            Button_New.Click += новыйToolStripMenuItem_Click;
            initial();
        }
        private void initial()
        {

            file_name = "";
            delete_type = 0;            //тип удаленного элемента
            x_cancel = 0;               //координаты удаленного элемента
            y_cancel = 0;
        }
        /// <summary>
        /// Удаление элемента диаграммы класс или комментарий
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void delete_KeyDown(object sender, KeyEventArgs e)
        {
            //очищаем данные о последнем удаленном элементе 
            delete_type = 0;
            cancel_comment = "";
            cancel_class.name = "";
            //if(cancel_class.properties.Count>0)
            //    cancel_class.properties.Clear();
            //if (cancel_class.metods.Count>0)
            //    cancel_class.metods.Clear();

            Control del = sender as Control;
            if (e.KeyCode == Keys.Delete)
            {
                //запоминаем этот объект, как последний удаляемый, чтобы была возможность отменить последнее удаление
                //если удаляемый объект класс
                if (del.GetType() == typeof(class_diagram_element))
                {
                    class_diagram_element cl1 = del as class_diagram_element;
                    //сохраняем параметры в соответствующую переменную
                    cancel_class = cl1.return_class();
                    delete_type = 1;
                }
                //если удаляемый объект комментарий
                else if (del.GetType() == typeof(comment_diagram_element))
                {
                    comment_diagram_element cde = del as comment_diagram_element;
                    //сохраняем параметры в соответствующую переменную
                    cancel_comment = cde.return_comment();
                    delete_type = 2;
                }

                //сохраняем координаты удаляемого элемента
                x_cancel = del.Location.X;
                y_cancel = del.Location.Y;

                //удаляем с рабочего поля элемент
                panel11.Controls.Remove(del);

                //делаем доступной кнопку отмены 
                Button_Cancel.Enabled = true;
                отменитьToolStripMenuItem.Enabled = true;
            }
        }
        /// <summary>
        /// Добавление класса на рабочее поле
        /// </summary>
        /// <param name="cl1"></param>
        private void add_class(class_diagram_element cl1)
        {

            panel11.Controls.Add(cl1);

            cl1.MouseMove += cl1_MouseMove;
            cl1.MouseDown += cl1_MouseDown;
            cl1.KeyDown += delete_KeyDown;
            cl1.ClassChanged += ClassEventHandler;

            //добавление контектстного меню
            System.Windows.Forms.ContextMenuStrip contextMenu1;
            contextMenu1 = new System.Windows.Forms.ContextMenuStrip();
            System.Windows.Forms.ToolStripMenuItem menuItem1;
            menuItem1 = new System.Windows.Forms.ToolStripMenuItem();
            System.Windows.Forms.ToolStripMenuItem menuItem2;
            menuItem2 = new System.Windows.Forms.ToolStripMenuItem();


            contextMenu1.Items.AddRange(new System.Windows.Forms.ToolStripMenuItem[] { menuItem1, menuItem2 });
            menuItem1.Text = "Добавить свойство";
            menuItem2.Text = "Добавить метод";


            cl1.ContextMenuStrip = contextMenu1;
            contextMenu1.Items[0].Click += add_class_attr_Click;
            contextMenu1.Items[1].Click += add_class_attr_Click;
        }
        private void ClassEventHandler(object sender, EventArgs e)
        {
            Control c = sender as Control;
            int x = c.Location.X;
            int y = c.Location.Y;
            if (sender_choose == false)
            {
                x_out = x;
                y_out = y;
                sender_choose = true;
            }
            else
            {
                if (x != x_out && y != y_out)
                {
                    x_in = x;
                    y_in = y;
                    sender_choose = false;

                    //отрисовка самой связи!!!!
                    isLinkAction = false;
                }
            }
        }
        /// <summary>
        /// Добавление нового класса по нажатию на кнопку
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_newClass_Click(object sender, EventArgs e)
        {
            //создание нового класса
            class_diagram_element cl1 = new class_diagram_element();
            add_class(cl1);
        }

        /// <summary>
        /// Добавление новых свойств и методов класса из контектсного меню
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void add_class_attr_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem tsmi = sender as ToolStripMenuItem;

            //Определяем контрол-источник,т.е. класс, в который необходимо что-либо добавить
            Control istochnik = ((ContextMenuStrip)tsmi.GetCurrentParent()).SourceControl;
            class_diagram_element cl = istochnik as class_diagram_element;

            //выбор действия: либо добавление свойства, либо добавление метода
            if (tsmi.Text == "Добавить свойство")
                cl.add_properties();
            else if (tsmi.Text == "Добавить метод")
                cl.add_method();
        }


        //движение мышью нашего чудесного класса

        private void cl1_MouseDown(object sender, MouseEventArgs e)
        {
            p = e.Location;
            Control a = sender as Control;
            a.BringToFront();
            s = a.Size;
        }

        //вот он красиво стал ездить по всему полю 
        private void cl1_MouseMove(object sender, MouseEventArgs e)
        {
            Control a = sender as Control;
            Size s0 = new Size(e.X - p.X, e.Y - p.Y);
            if (e.Button == MouseButtons.Left)
            {
                Point p0 = a.Location + s0;
                a.Location = new Point(Math.Max(0, p0.X), Math.Max(0, p0.Y));
            }
            else
                if (e.Button == MouseButtons.Right)
                {
                    s0 += s;
                    a.Size = new Size(Math.Max(50, s0.Width), Math.Max(20, s0.Height));
                }
        }

        private void add_Comment(comment_diagram_element cl1)
        {
            panel11.Controls.Add(cl1);

            cl1.MouseMove += cl1_MouseMove;
            cl1.MouseDown += cl1_MouseDown;
            cl1.KeyDown += delete_KeyDown;
            cl1.CommentChanged+= ClassEventHandler;
        }

        private void Button_Coments_Click(object sender, EventArgs e)
        {
            comment_diagram_element cl1 = new comment_diagram_element();
            add_Comment(cl1);

        }
        private void новыйToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult res = MessageBox.Show("Сохранить текущую диаграмму?", "UML редактор", MessageBoxButtons.OKCancel);
            if (res == DialogResult.OK)
            {
                // сохранить
                save();
            }
            clean_panel(); //очистить рабочую область
            initial();

            ///////инициализация данных для связей!!!!//////
            //OpenFileDialog dial = new OpenFileDialog();
            //dial.FileName = "Новая диаграмма";
            //dial.DefaultExt = "xml";
            //dial.Filter = "Файлы XML(*.xml)|*xml";
            //if (dial.ShowDialog() != DialogResult.OK)
            //    return;
            //try
            //{
            //    file_name = dial.FileName;
            //    load_Diadramm();
            //}
            //catch (Exception ex)
            //{
            //    MessageBox.Show("Error" + ex.Message);
            //}
        }
        /// <summary>
        /// очистить рабочее поле
        /// </summary>
        /// 
        private void clean_panel()
        {
            panel11.Controls.Clear();
            //!!!убираем связи!!!

        }

        /// <summary>
        /// !!!!считывание из XML!!!!/////////
        /// </summary>
        private void load_Diadramm()
        {
            string CCX = "0", CCY = "0";
            string tCComX = "0", tCComY = "0";

            OpenFileDialog openDlg = new OpenFileDialog();
            openDlg.Filter = "Файлы XML (*.xml)|*.xml";
            if (openDlg.ShowDialog() != DialogResult.OK)
            { return; }
            file_name = openDlg.FileName;
            XmlTextReader reader = null;
            try
            {

                reader = new XmlTextReader(openDlg.FileName);
                //пропустить все пустые узлы
                reader.WhitespaceHandling = WhitespaceHandling.None;
                //*! пробная переменная, заменить на нормальные
                string name;
                //*!
                XmlDocument doc = new XmlDocument();
                while (reader.Read())
                {
                    XmlNodeType dType = reader.NodeType;
                    if (dType == XmlNodeType.Element)
                    {
                        //******!!!!Класс с именем, свойствами, методами.  
                        if (reader.Name == "Class")
                        {
                            class_element my_class = new class_element();
                            List<string> prop = new List<string>();
                             List<string> met = new List<string>();
                            if (reader.Read() && reader.Name == "ClassName")
                            {
                                my_class.name = reader.ReadInnerXml();
                                if (reader.Name == "Properties")
                                {
                                    reader.Read();
                                    if (reader.Name == "TextProperties")
                                    {
                                        while (reader.Name == "TextProperties")
                                        { 
                                            prop.Add(reader.ReadInnerXml());
                                        }
                                        reader.Read();
                                    }
                                    
                                    
                                }
                                if (reader.Name == "Methods")
                                {
                                    reader.Read();
                                    if (reader.Name == "MethodsText")
                                    {
                                        while (reader.Name == "MethodsText")
                                        {
                                            met.Add(reader.ReadInnerXml());
                                        }
                                        reader.Read();
                                    }
                                }
                               
                                if (reader.Name == "CoordinateClassX")
                                {
                                    CCX = reader.ReadInnerXml();

                                }
                           
                                if (reader.Name == "CoordinateClassY")
                                {
                                    CCY = reader.ReadInnerXml();
                                }
                                my_class.properties = prop;
                                my_class.metods = met;
                                class_diagram_element cl1 = new class_diagram_element();
                                add_class(cl1);
                                cl1.load_class(my_class);
                                //исправить с приведением типов
                                cl1.Location = new Point(Convert.ToInt32(CCX), Convert.ToInt32(CCY));
                            }
                        }
                        //////******!!!!!Комментарий
                        if (reader.Name == "Comment")
                        {
                            comment_diagram_element cde = new comment_diagram_element();
                            if (reader.Read() && reader.Name == "TextComment")
                            {
                                add_Comment(cde);
                                cde.import_comment(reader.ReadInnerXml());
                            }
                            if (reader.Name == "CoordinateCommentsX")
                            {
                                tCComX = reader.ReadInnerXml();
                            }
                            if (reader.Name == "CoordinateCommentsY")
                            {
                                tCComY = reader.ReadInnerXml();
                            }
                            //исправить с приведением типов! 
                            cde.Location = new Point(Convert.ToInt32(tCComX), Convert.ToInt32(tCComY));
                        }
                        //****!!!!!!!!!!!!!!!LINK LINK LINK for commit
                        //if (reader.Name == "Link")
                        //{
                        //    if (reader.Name == "Type")
                        //    {
                        //        string tlt = reader.ReadInnerXml();
                        //    }
                        //    if (reader.Name == "CoordinateX1")
                        //    {
                        //        string tltx1 = reader.ReadInnerXml();
                        //    }
                        //    if (reader.Name == "CoordinateY1")
                        //    {
                        //        string tlty1 = reader.ReadInnerXml();
                        //    }
                        //    if (reader.Name == "CoordinateX2")
                        //    {
                        //        string tltx2 = reader.ReadInnerXml();
                        //    }
                        //    if (reader.Name == "CoordinateY2")
                        //    {
                        //        string tlty2 = reader.ReadInnerXml();
                        //    }
                        //    if (reader.Name == "Stereotype")
                        //    {
                        //        if (reader.Name == "TextStereotype")
                        //        {
                        //            string tlStx= reader.ReadInnerXml();
                        //        }
                        //    }
                        //}

                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error:" + ex.Message);
            }

        }
        /// <summary>
        ///*!!!!Учитывая, что кроме меню, у нас тул бар, выношу свою функцию 
        ///*!!!!записи в файл в отдельную ф-цию
        /// </summary>

        private void save_Diagramm()
        {

            //XmlTextWriter writer = null;
            try
            {
                XmlDocument diagramm = new XmlDocument();
                // создание дерева вариант 2
                XmlDeclaration dec = diagramm.CreateXmlDeclaration("1.0", null, null);
                diagramm.AppendChild(dec);
                XmlElement root = diagramm.CreateElement("ClassDiagram");
                diagramm.AppendChild(root);
                XmlElement Classes = diagramm.CreateElement("Classes");
                root.AppendChild(Classes);

                //добавим красивый цикл по созданию Н классов
                foreach (Control cnt in panel11.Controls)
                {

                    if (cnt.GetType() == typeof(class_diagram_element))
                    {
                        class_diagram_element cl1 = cnt as class_diagram_element;
                        class_element my_class = new class_element();
                        my_class = cl1.return_class();
                        XmlElement Class = diagramm.CreateElement("Class");
                        Classes.AppendChild(Class);
                        XmlElement NameClass = diagramm.CreateElement("ClassName");
                        NameClass.InnerText = my_class.name;

                        //Красиво создаём в цикле которого пока ещё нет Н свойств.текст в ковычках который пойдёт в тэги надо заменить переменными
                        XmlElement Properties = diagramm.CreateElement("Properties");
                        for (int i = 0; i < my_class.properties.Count; i++)
                        {
                            XmlElement TextProperties = diagramm.CreateElement("TextProperties");
                            TextProperties.InnerText = my_class.properties[i];
                            Properties.AppendChild(TextProperties);
                        }

                        //**!!Создаём в цикле которого ещё нет Н методов.текст в ковычках который пойдёт в тэги надо заменить переменными
                        XmlElement Methods = diagramm.CreateElement("Methods");
                        for (int i = 0; i < my_class.metods.Count; i++)
                        {
                            XmlElement MethodsText = diagramm.CreateElement("MethodsText");
                            MethodsText.InnerText = my_class.metods[i];
                            Methods.AppendChild(MethodsText);
                        }
                        //глобальные координаты элемента
                        XmlElement CoordinateClassX = diagramm.CreateElement("CoordinateClassX");
                        CoordinateClassX.InnerText = cl1.Location.X.ToString();

                        XmlElement CoordinateClassY = diagramm.CreateElement("CoordinateClassY");
                        CoordinateClassY.InnerText = cl1.Location.Y.ToString();

                        Class.AppendChild(NameClass);
                        Class.AppendChild(Properties);
                        Class.AppendChild(Methods);
                        Class.AppendChild(CoordinateClassX);
                        Class.AppendChild(CoordinateClassY);

                    }

                }
                XmlElement Comments = diagramm.CreateElement("Comments");
                root.AppendChild(Comments);
                foreach (Control cnt in panel11.Controls)
                {
                    if (cnt.GetType() == typeof(comment_diagram_element))
                    {
                        comment_diagram_element cde = cnt as comment_diagram_element;
                        XmlElement Comment = diagramm.CreateElement("Comment");
                        Comments.AppendChild(Comment);

                        XmlElement TextComment = diagramm.CreateElement("TextComment");
                        TextComment.InnerText = cde.return_comment();
                        Comment.AppendChild(TextComment);

                        XmlElement CoordinateCommentsX = diagramm.CreateElement("CoordinateCommentsX");
                        CoordinateCommentsX.InnerText = cde.Location.X.ToString();

                        XmlElement CoordinateCommentsY = diagramm.CreateElement("CoordinateCommentsY");
                        CoordinateCommentsY.InnerText = cde.Location.Y.ToString();
                        Comment.AppendChild(CoordinateCommentsX);
                        Comment.AppendChild(CoordinateCommentsY);
                    }
                }

                //////////////////////////////////////СВЯЗИ!!!!!!!!!!!!!!!!!!!!///////////////////////////////
                //*создаём связи.текст в ковычках который пойдёт в тэги надо заменить переменными
                XmlElement Links = diagramm.CreateElement("Links");
                root.AppendChild(Links);
                // вновь необходимо цикл по созданию всех связей
                XmlElement Link = diagramm.CreateElement("Link");
                Links.AppendChild(Link);
                XmlElement Type = diagramm.CreateElement("Type");
                Type.InnerText = "Введите";
                XmlElement CoordinateX1 = diagramm.CreateElement("CoordinateX1");
                CoordinateX1.InnerText = "Введите";
                XmlElement CoordinateY1 = diagramm.CreateElement("CoordinateY1");
                CoordinateY1.InnerText = "Введите";
                XmlElement CoordinateX2 = diagramm.CreateElement("CoordinateX2");
                CoordinateX2.InnerText = "Введите";
                XmlElement CoordinateY2 = diagramm.CreateElement("CoordinateY2");
                CoordinateY2.InnerText = "Введите";
                XmlElement Stereotype = diagramm.CreateElement("Stereotype");
                XmlElement TextStereotype = diagramm.CreateElement("TextStereotype");
                TextStereotype.InnerText = "Введите текст стереотипа";
                Stereotype.AppendChild(TextStereotype);
                Link.AppendChild(Type);
                Link.AppendChild(CoordinateX1);
                Link.AppendChild(CoordinateY1);
                Link.AppendChild(CoordinateX2);
                Link.AppendChild(CoordinateY2);
                Link.AppendChild(Stereotype);

                //а вот тут красиво записали в файл
                diagramm.Save(file_name/*saveNewDg.FileName*/);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error" + ex.Message);
            }

        }
        private void save()
        {
            if (file_name != "")
                save_Diagramm();
            else
            {
                SaveFileDialog saveNewDg = new SaveFileDialog();
                saveNewDg.FileName = "Новая диаграмма";
                saveNewDg.DefaultExt = "xml";
                saveNewDg.Filter = "Файлы XML(*.xml)|*xml";
                if (saveNewDg.ShowDialog() != DialogResult.OK)
                    return;
                file_name = saveNewDg.FileName;
                save_Diagramm();
            }

        }
        private void сохранитьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            save();
        }

        private void Button_Save_Click(object sender, EventArgs e)
        {
            save();
        }

        private void открытьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult res = MessageBox.Show("Сохранить текущую диаграмму?", "UML редактор", MessageBoxButtons.OKCancel);
            if (res == DialogResult.OK)
            {
                // сохранить
                save();
            }
            clean_panel(); //очистить рабочую область
            initial();
            load_Diadramm();
        }

        private void Вutton_Open_Click(object sender, EventArgs e)
        {
            DialogResult res = MessageBox.Show("Сохранить текущую диаграмму?", "UML редактор", MessageBoxButtons.OKCancel);
            if (res == DialogResult.OK)
            {
                // сохранить
                save();
            }
            clean_panel(); //очистить рабочую область
            initial();
            load_Diadramm();
        }

        /// <summary>
        /// Возврат на рабочее поле последнего удаленного элемента диаграммы класс или комментарий
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cancel_Last_Delete(object sender, EventArgs e)
        {
            //если последний удаленный эелемент был классом
            if (delete_type == 1)
            {
                //создаем класс с сохраненными при удалении параметрами
                class_diagram_element cl1 = new class_diagram_element();
                add_class(cl1);
                cl1.load_class(cancel_class);

                cancel_class.name = "";
                cancel_class.properties.Clear();
                cancel_class.metods.Clear();

                //перемещаем вновь созданный класс на место до удаления
                cl1.Location = new Point(x_cancel, y_cancel);

            }
            //если последний удаленный эелемент был комментарием
            else if (delete_type == 2)
            {
                //создаем комментарий с сохраненными при удалении параметрами
                comment_diagram_element cde = new comment_diagram_element();
                add_Comment(cde);
                cde.import_comment(cancel_comment);

                cancel_comment = "";

                //перемещаем вновь созданный класс на место до удаления
                cde.Location = new Point(x_cancel, y_cancel);
            }
            //очищаем данные о последнем удаленном элементе до появления новых удалений
            delete_type = 0;
            Button_Cancel.Enabled = false;
            отменитьToolStripMenuItem.Enabled = false;


        }

        private void сохранитьКакToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveNewDg = new SaveFileDialog();
            saveNewDg.FileName = "Новая диаграмма";
            saveNewDg.DefaultExt = "xml";
            saveNewDg.Filter = "Файлы XML(*.xml)|*xml";
            if (saveNewDg.ShowDialog() != DialogResult.OK)
                return;
            file_name = saveNewDg.FileName;
            save_Diagramm();
        }

        private void Button_unidirectional_Click(object sender, EventArgs e)
        {
            isLinkAction = true;
        }


    }
}
